Flash Gallery | Flash Templates | Flash Menu | Flash Design | Flash Audio & Video

Video Corsi Actionscript 3.0


+ Reply to Thread
Results 1 to 4 of 4

Thread: Gioco Flash tutorial

  1. #1
    Administrator Living At The FlepStudio! Flep is on a distinguished road
    Join Date
    Jul 2007
    Posts
    5,460
    Rep Power
    8

    Gioco Flash tutorial

    amazing Flash templates

    Questo articolo è un tutorial che spiega come poter creare un gioco con Flash CS3.

    Il gioco che prenderò in esame potete vederlo a questo link. ( segnalato da Daniele )

    Chiaramente mi limiterò a spiegare la logica che utilizza il gioco in questione e non andrò a creare nessun tipo di grafiche.

    A voi basterà cambiare le grafiche delle MovieClip utilizzate per personalizzare il gioco a vostro piacimento.

    Vorrei anche ricordare che utilizzare le stesse grafiche del gioco originale, potrebbe essere illegale.


    Pronti ? Via...



    Creo un FLA che salvo con nome ' main.fla ' , al cui interno:

    - una MovieClip a cui do nome istanza bg_mc ( sarà la MovieClip che fa da sfondo )

    - una MovieClip a cui do nome istanza ' gallina_mc ' ( sarà la gallina che lancia le uova )

    - una MovieClip a cui do nome istanza ' cesto_mc ' ( sarà il cesto che raccoglie le uova )

    - una MovieClip a cui do nome istanza ' linea_mc ' ( sarà la linea per cui se le uova la oltrepassano finisce il gioco )

    - una MovieClip a cui do nome istanza ' cambia_livello_mc ' ( sarà la clip che avviserà l' utente di aver superato un livello e quindi cliccarla per proseguire )

    - una MovieClip a cui do nome istanza ' game_over_mc ' ( sarà la clip che avvisa il giocatore quando il gioco è finito e quindi cliccarla per ricominciare da capo )

    - una MovieClip che lascio in libreria con nome ' mc_uovo ' ( sarà la clip che istanzierò in runtime ...ex metodo attachMovie...e fungerà da uovo )

    - un campo di testo dinamico che chiamo ' punteggio_txt ' ( sarà il campo di testo che visualizzarà il punteggio del giocatore )

    - un campo di testo dinamico che chiamo ' livello_txt ' ( sarà il campo di testo che visualizzerà il livello del gioco in corso )


    Creo la Document Class, un file AS che salvo con nome ' Main.as ', implementata in questo modo:


    Code:
    package
    {
    	import flash.display.MovieClip;
    	import flash.text.TextField;
    	import flash.utils.Timer;
    	import flash.events.*;
    	
    	public class Main extends MovieClip
    	{
    		private var timer:Timer;
    		private var timer_uova:Timer;
    		
    		public static var livello:int=1;
    		private var cambio:Number;
    		private var numUova:int=10;
    		public var punteggio:int=0;
    		
    		private var isPressed:Boolean=false;
    		private var direzione:Boolean=true;
    		private var destra:Boolean=false;
    		private var sinistra:Boolean=false;
    		
    		public function Main()
    		{
    			init();
    			attivaTimer();
    			listeners();
    			lanciaUova();
    		}
    		
    		private function init():void
    		{
    			stage.frameRate=31;
    			
    			gallina_mc.x=stage.stageWidth/2;
    			gallina_mc.y=gallina_mc.height+10;
    			
    			cambio=1000+Math.floor(Math.random()*6000);
    			
    			cambia_livello_mc.visible=false;
    			game_over_mc.visible=false;
    			punteggio_txt.text='punteggio: '+punteggio;
    		}
    		
    		private function attivaTimer():void
    		{
    			livello_txt.text='livello: '+livello;
    			timer=new Timer(cambio,1);
    			timer.addEventListener(TimerEvent.TIMER,lanciaNumero);
    			timer.start();
    		}
    		
    		private function lanciaNumero(t:TimerEvent):void
    		{
    			cambio=1000+Math.floor(Math.random()*4000);
    			livello*=-1;
    			attivaTimer();
    		}
    		
    		private function listeners():void
    		{
    			this.addEventListener(MouseEvent.MOUSE_DOWN,settaFocus);
    			gallina_mc.addEventListener(Event.ENTER_FRAME,muoviGallina);
    			cesto_mc.addEventListener(Event.ENTER_FRAME,muoviCesto);
    			stage.stageFocusRect=false;
    			stage.focus=this;
    			this.addEventListener(KeyboardEvent.KEY_DOWN,controllaTasto);
    			this.addEventListener(KeyboardEvent.KEY_UP,azzeraTasto);
    		}
    		
    		private function settaFocus(m:MouseEvent):void
    		{
    			stage.focus=this;
    		}
    		
    		private function muoviGallina(e:Event):void
    		{
    			gallina_mc.x+=livello*4;
    			if(gallina_mc.x>=stage.stageWidth-gallina_mc.width/2)
    				livello*=-1;
    			if(gallina_mc.x<=gallina_mc.width/2)
    				livello*=-1;
    		}
    		
    		private function muoviCesto(e:Event):void
    		{
    			if(isPressed&&direzione)
    				e.target.x+=Math.abs(livello)*5;
    			if(isPressed&&!direzione)
    				e.target.x-=Math.abs(livello)*5;
    		}
    		
    		private function controllaTasto(k:KeyboardEvent):void
    		{
    			isPressed=true;
    			if(k.keyCode==39)
    			{
    				destra=true;
    				direzione=true;
    			}
    			if(k.keyCode==37)
    			{
    				sinistra=true;
    				direzione=false;
    			}
    			k.updateAfterEvent();
    		}
    		
    		private function azzeraTasto(k:KeyboardEvent):void
    		{
    			if(k.keyCode==39)
    				destra=false;
    			if(k.keyCode==37)
    				sinistra=false;
    			if(!destra&&!sinistra)
    				isPressed=false;
    		}
    		
    		private function lanciaUova():void
    		{
    			timer_uova=new Timer(1000-Math.abs(livello)*100,numUova);
    			timer_uova.addEventListener(TimerEvent.TIMER,sgancia);
    			timer_uova.start();
    		}
    		
    		private function sgancia(t:TimerEvent):void
    		{
    			var uovo:Uovo=new Uovo(this,timer_uova.currentCount);
    		}
    		
    		public function passaLivello():void
    		{
    			timer.stop();
    			this.removeEventListener(MouseEvent.MOUSE_DOWN,settaFocus);
    			gallina_mc.removeEventListener(Event.ENTER_FRAME,muoviGallina);
    			cesto_mc.removeEventListener(Event.ENTER_FRAME,muoviCesto);
    			this.removeEventListener(KeyboardEvent.KEY_DOWN,controllaTasto);
    			this.removeEventListener(KeyboardEvent.KEY_UP,azzeraTasto);
    			
    			cambia_livello_mc.visible=true;
    			cambia_livello_mc.addEventListener(MouseEvent.MOUSE_DOWN,avanza);
    		}
    		
    		private function avanza(m:MouseEvent):void
    		{
    			livello=Math.abs(livello);
    			livello++;
    			attivaTimer();
    			listeners();
    			lanciaUova();
    			cambia_livello_mc.visible=false;
    		}
    		
    		public function gameOver():void
    		{
    			timer.stop();
    			timer_uova.stop();
    			this.removeEventListener(MouseEvent.MOUSE_DOWN,settaFocus);
    			gallina_mc.removeEventListener(Event.ENTER_FRAME,muoviGallina);
    			cesto_mc.removeEventListener(Event.ENTER_FRAME,muoviCesto);
    			this.removeEventListener(KeyboardEvent.KEY_DOWN,controllaTasto);
    			this.removeEventListener(KeyboardEvent.KEY_UP,azzeraTasto);
    			
    			game_over_mc.visible=true;
    			game_over_mc.addEventListener(MouseEvent.MOUSE_DOWN,riprova);
    		}
    		
    		private function riprova(m:MouseEvent):void
    		{
    			livello=1;
    			punteggio=0;
    			punteggio_txt.text='punteggio: '+punteggio;
    			attivaTimer();
    			listeners();
    			lanciaUova();
    			game_over_mc.visible=false;
    		}
    	}
    }
    Creo la classe Uovo, un file AS che salvo con nome ' Uovo.as ', implementata in questo modo:
    Code:
    package
    {
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	
    	public class Uovo extends MovieClip
    	{
    		private var Root:MovieClip;
    		
    		private var id:int;
    		
    		public function Uovo(m:MovieClip,n:int)
    		{
    			Root=m;
    			id=n;
    			Root.addChild(this);
    			init();
    		}
    		
    		private function init():void
    		{
    			x=Root.gallina_mc.x;
    			y=Root.gallina_mc.y;
    			this.addEventListener(Event.ENTER_FRAME,cadi);
    		}
    		
    		private function cadi(e:Event):void
    		{
    			y+=Math.abs(Main.livello)*3;
    			if(this.hitTestObject(Root.cesto_mc))
    			{
    				this.removeEventListener(Event.ENTER_FRAME,cadi);
    				Root.removeChild(this);
    				Root.punteggio++;
    				Root.punteggio_txt.text='punteggio: '+Root.punteggio;
    				if(id==10)
    					Root.passaLivello();
    			}
    			
    			if(y>=Root.linea_mc.y)
    			{
    				this.removeEventListener(Event.ENTER_FRAME,cadi);
    				Root.gameOver();
    			}
    		}
    	}
    }
    Risultato:










    Analizziamo il codice passo per passo.

    - le proprietà che ho creato nella Document Class:
    due variabili Timer che utilizzo per cambiare la direzione di gallina_mc e per lanciare le uova ad ogni intervallo
    private var timer:Timer;
    private var timer_uova:Timer;
    una variabile numerica ( numero intero per cui classe int ) che utilizzo per il livello di difficoltà del gioco
    public var livello:int=1;
    una variabile numerica che memorizza un intervallo di tempo random con cui cambio la direzione di gallina_mc
    private var cambio:Number;
    una variabile numerica che indica il numero totale di uova che la gallina lancia per ogni livello
    private var numUova:int=10;
    una variabile numerica con cui memorizzo il punteggio del giocatore
    public var punteggio:int=0;
    quattro variabili booleane che utilizzo per le logiche condizionali del movimento del giocatore su cesto_mc utilizzando la tastiera
    private var isPressed:Boolean=false;
    private var direzione:Boolean=true;
    private var destra:Boolean=false;
    private var sinistra:Boolean=false;

    - i metodi della Document Class ( Main.as )
    init();
    assegno il frame rate della timeline
    stage.frameRate=31;
    posiziono gallina_mc
    gallina_mc.x=stage.stageWidth/2;
    gallina_mc.y=gallina_mc.height+10;
    assegno un valore alla variabile ' cambio '
    cambio=1000+Math.floor(Math.random()*6000);
    faccio sparire cambia_livello_mc e game_over_mc
    cambia_livello_mc.visible=false;
    game_over_mc.visible=false;
    assegno un testo al campo di testo del punteggio
    punteggio_txt.text='punteggio: '+punteggio;

    attivaTimer();
    assegno un testo a livello_txt che aggiorna il giocatore a che livello si trova
    livello_txt.text='livello: '+livello;
    dichiaro l' istanza timer che chiamerà dopo tot secondi ( in base al valore della variabile numerica ' cambio ' ) per una volta sola il metodo lanciaNumero() e vedremo perchè...
    timer=new Timer(cambio,1);
    timer.addEventListener(TimerEvent.TIMER,lanciaNume ro);
    timer.start();

    lanciaNumero();
    aggiorno ' cambio ' con un altro numero random che è un secondo più un numero approssimato per difetto tra zero e 4000 ( quindi 1000 millesimi + numero random tra 0 e 4000 millesimi )
    cambio=1000+Math.floor(Math.random()*4000);
    inverto il segno della variabile numerica ' livello ' ( qualsiasi numero moltiplicato per -1 mantiene il proprio valore ma cambia di segno ) vedremo perchè...
    livello*=-1;
    richiamo il metodo attivaTimer()
    attivaTimer();

    listeners();
    Aggiungo i listeners in ascolto che necessito per richiamare metodi.
    Dico a Flash che per ogni click che avviene sullo Stage di chiamare la funzione/metodo settaFocus()
    this.addEventListener(MouseEvent.MOUSE_DOWN,settaF ocus);
    dico a gallina_mc di creare un intervallo ( ENTER_FRAME ) che chiama il metodo muoviGallina()
    gallina_mc.addEventListener(Event.ENTER_FRAME,muov iGallina);
    dico a cesto_mc di creare un intervallo ( ENTER_FRAME ) che chiama il metodo muoviCesto()
    cesto_mc.addEventListener(Event.ENTER_FRAME,muoviC esto);
    dico allo stge di non visualizzare il quadratino di fuoco sulle clip a cui applicherò il fuoco
    stage.stageFocusRect=false;
    assegno il fuoco ( focus ) a questa classe ( che non è altro che la timeline, un' istanza della classe MovieClip)
    stage.focus=this;
    dico a Flash di mettersi in ascolto di quando l' utente premerà un tasto sulla tastiera
    this.addEventListener(KeyboardEvent.KEY_DOWN,contr ollaTasto);
    dico a Flash di mettersi in ascolto di quando l' utente rilascerà un tasto della tastiera
    this.addEventListener(KeyboardEvent.KEY_UP,azzeraT asto);

    settaFocus();
    assegno il fuoco a tutto lo stage
    stage.focus=this;

    muoviGallina();
    faccio avanzare la gallina ( ricordiamoci che siamo sotto intervallo ENTER_FRAME ) di un valore pari al valore della variabile livello moltiplicata per 4
    gallina_mc.x+=livello*4;
    applico delle logiche condizionali per cui se gallina_mc arriva a fine stage, oppure si trova più indietro dell'inzio dello stage cambio il segno del valore con cui sta avanzando ( ecco il perchè del *=-1 )
    if(gallina_mc.x>=stage.stageWidth-gallina_mc.width/2)
    livello*=-1;
    if(gallina_mc.x<=gallina_mc.width/2)
    livello*=-1;

    muoviCesto();
    controllo il movimento di cesto_mc sui tasti DESTRA e SINISTRA della tastiera applicando delle logiche condizionali ( e.target significa chi ha dispacciato l' evento, in questo caso cesto_mc )
    if(isPressed&&direzione)
    e.target.x+=Math.abs(livello)*5;
    if(isPressed&&!direzione)
    e.target.x-=Math.abs(livello)*5;

    NB: Spiegare precisamente le logiche condizionali è davvero difficilissimo, sono calcoli che si fanno in fase di sviluppo dell' applicazione e quindi suggerisco di studiarle per come sono oppure di applicarne altre a vostro piacimento

    controllaTasto();
    Anche quì applico delle logiche condizionali per controllare quando i tasti DESTRA e SINISTRA vengono premuti. A quel punto cambio il valore di alcune variabili booleane
    isPressed=true;
    if(k.keyCode==39)
    {
    destra=true;
    direzione=true;
    }
    if(k.keyCode==37)
    {
    sinistra=true;
    direzione=false;
    }

    azzeraTasto();
    Stessa cosa anche quì, applico logiche condizionali sull' evento del rilascio di un tasto della tastiera
    if(k.keyCode==39)
    destra=false;
    if(k.keyCode==37)
    sinistra=false;
    if(!destra&&!sinistra)
    isPressed=false;

    lanciaUova();
    dichiaro l' istanza timer che chiamerà ogni tot secondi ( in base al valore di 1000 meno il numero assoluto, quindi sempre con segno positivo, della variabile ' livello ' moltiplicato per un centesimo di secondo ) il metodo sgancia() di tante volte quanto il valore della variabile ' numUova '
    timer_uova=new Timer(1000-Math.abs(livello)*100,numUova);
    timer_uova.addEventListener(TimerEvent.TIMER,sganc ia);
    timer_uova.start();

    sgancia();
    istanzio la classe Uovo.as che non fa altro che attaccare una MovieClip da libreria, per cui torno su main.fla, click col destro in libreria su mc_uovo, attivo l' opzione esporta per Actionscript e nel campo Class inserisco Uovo. Alla classe Uovo.as passo i valori di this ( cioè la Document Class, la timeline, la root...chiamatela come volete ) ed un valore numerico che è il numero di volte che timer_uova ha chiamato appunto questo metodo sgancia()
    var uovo:Uovo=new Uovo(this,timer_uova.currentCount);


    passaLivello();
    questo metodo viene chiamato dalla classe Uovo.as ( infatti ha attributo public ) e poi vedremo quando viene chiamato...
    non fa altro che fermare timer
    timer.stop();
    rimuovere tutti i listeners in ascolto ( così libero memoria )
    this.removeEventListener(MouseEvent.MOUSE_DOWN,set taFocus);
    gallina_mc.removeEventListener(Event.ENTER_FRAME,m uoviGallina);
    cesto_mc.removeEventListener(Event.ENTER_FRAME,muo viCesto);
    this.removeEventListener(KeyboardEvent.KEY_DOWN,co ntrollaTasto);
    this.removeEventListener(KeyboardEvent.KEY_UP,azze raTasto);
    faccio diventare visibile la MovieClip cambia_livello_mc
    cambia_livello_mc.visible=true;
    assegno un listener in ascolto su cambia_livello_mc in modo da sapere quando viene cliccata e a quel punto Flash chiamerà il metodo avanza()
    cambia_livello_mc.addEventListener(MouseEvent.MOUS E_DOWN,avanza);

    avanza();
    quando cambia_livello_mc viene cliccato viene chiamato questo metodo che...
    converte il segno del valore della variabile livello a positivo
    livello=Math.abs(livello);
    incrementa di uno il valore della variabile livello
    livello++;
    richiama il metodo attivaTimer();
    attivaTimer();
    agiiunge dei nuovi listeners in ascolto
    listeners();
    richiama il metodo lanciaUova()
    lanciaUova();
    rimetto a invisibile cambia_livello_mc
    cambia_livello_mc.visible=false;

    NB: vengono richiamati gli stessi metodi che all' inizio la funzione costruttrice Main chiama... public function Main()


    gameOver();
    questo metodo viene chiamato a certe condizioni dalla classe Uovo e vedremo come...
    fermo i due timers
    timer.stop();
    timer_uova.stop();
    rimuovo tutti i listeners in ascolto
    this.removeEventListener(MouseEvent.MOUSE_DOWN,set taFocus);
    gallina_mc.removeEventListener(Event.ENTER_FRAME,m uoviGallina);
    cesto_mc.removeEventListener(Event.ENTER_FRAME,muo viCesto);
    this.removeEventListener(KeyboardEvent.KEY_DOWN,co ntrollaTasto);
    this.removeEventListener(KeyboardEvent.KEY_UP,azze raTasto);
    faccio vedere la MovieClip game_over_mc
    game_over_mc.visible=true;
    assegno un listener in ascolto su game_over_mc in modo da sapere quando viene cliccata e a quel punto Flash chiamerà il metodo riprova()
    game_over_mc.addEventListener(MouseEvent.MOUSE_DOW N,riprova);

    riprova();
    quando game_over_mc viene cliccato viene chiamato questo metodo che...
    riporto livello a uno
    livello=1;
    riporto il punteggio a zero
    punteggio=0;
    assegno del testo a punteggio_txt
    punteggio_txt.text='punteggio: '+punteggio;
    richiamo i metodi della funzione costrutrice....public function Main()
    attivaTimer();
    listeners();
    lanciaUova();
    rimetto a invisibile game_over_mc
    game_over_mc.visible=false;

    Passiamo ora ad analizzare la classe Uovo.
    Proprietà:
    - Root:MovieClip ( la root dell'applicazione, la Document Class )
    - id:Number ( un numero di identificazione che viene passato da Main.as )
    infatti la funzione costruttrice della classe Uovo si aspetta 2 parametri:
    public function Uovo(m:MovieClip,n:int)
    imposto il valore di ' Root ' uguale al valore di ' m ' che mi passa Main.as
    Root=m;
    imposto il valore di ' id ' uguale al valore di ' n ' che mi passa Main.as
    id=n;
    aggiungo al DisplayObject questa classe ( non dimentichiamoci che il ' this ' quì si riferisce alla MovieClip mc_uovo che abbiamo in libreria e che verrà attaccata )
    Root.addChild(this);
    chiamo il metodo init
    init();

    Metodi:
    init();
    posiziono la MovieClip
    x=Root.gallina_mc.x;
    y=Root.gallina_mc.y;
    creo un listener in ascolto dell' intervallo ENTER_FRAME che chiamerà il metodo cadi() tante volta al secondo quanto è il valore del framerate
    this.addEventListener(Event.ENTER_FRAME,cadi);



    cadi();
    dico all' uovo di aumentare la y di un valore pari al valore assoluto della variabile livello di Main.as ( che è Root ) moltiplicato per tre
    y+=Math.abs(Root.livello)*3;
    controllo se l' uovo collide con cesto_mc
    if(this.hitTestObject(Root.cesto_mc))
    {
    se collide, fermo l' intervallo rimuovendo il listener
    this.removeEventListener(Event.ENTER_FRAME,cadi);
    rimuovo l' uovo dalle stage
    Root.removeChild(this);
    incremento la variabile punteggio di Main.as
    Root.punteggio++;
    assegno un testo a punteggio_txt
    Root.punteggio_txt.text='punteggio: '+Root.punteggio;
    controllo se l' uovo che ha appena toccato cesto_mc è l'ultimo chiedendo se il suo id è uguale al valore della variabile numUova di Main.as
    if(id==Root.numUova)
    se si, chiamo il metodo passaLivello() di Main.as che abbiamo già visto cosa eseguirà
    Root.passaLivello();
    }
    controllo se la y dell' uovo è maggiore della y di linea_mc
    if(y>=Root.linea_mc.y)
    {
    se si, fermol' intervallo rimuovendo il listener
    this.removeEventListener(Event.ENTER_FRAME,cadi);
    chiamo il metodo gameOver() della classe Main che abbiamo già visto cosa eseguirà
    Root.gameOver();
    }

    Allego i files sorgente:
    Attached Files

  2. #2
    Junior Member Settled In carlitos_way is on a distinguished road
    Join Date
    Nov 2008
    Posts
    2
    Rep Power
    0

    Re: Gioco Flash tutorial

    ciao a tutti, ho notato un errore nel programma in quanto la pressione di tasti diversi dalle frecce destra e sinistra fanno si che il cesto continui a muoversi.

    per sistemare il problema basta commentare l'utilizzo della variabile booleana ed aggiornare la funzione muoviCesto nel seguente modo:
    private function muoviMassa(e:Event):void
    {
    // movimento di massa
    if (isPressed&&destra)
    e.target.x+=Math.abs(livello*5);
    if (isPressed&&sinistra)
    e.target.x-=Math.abs(livello)*5;
    }
    Last edited by carlitos_way; 04-11-08 at 10:04.

  3. #3
    Junior Member Settled In carlitos_way is on a distinguished road
    Join Date
    Nov 2008
    Posts
    2
    Rep Power
    0

    Re: Gioco Flash tutorial

    scusate il doppio post ma dopo l'invio del messaggio continua a caricare e non capisco se ha inviato effettivamente o no...

  4. #4
    Junior Member Settled In DjRiKyX is on a distinguished road
    Join Date
    Nov 2008
    Posts
    12
    Rep Power
    0

    Re: Gioco Flash tutorial

    salve a tutti... ci sono dei problemini che ho notato.. se continuo a muovermi con il cesto.. sia verso destra o verso sinistra.. il cesto esce dallo stage...

    poi.. quando le uova cadono nella linea di gameover.. se io rinizio il gioco.. se ci sono ancora delle uova in aria e cadono.. il gioco finisce ancora..

    per questo problema.. propongo un reset completo.. cioè.. quando c'è il game over.. tutte le uova che ci sono.. spariscono dallo stage...

    io purtroppo non sono in grado di correggere questi problemi in quanto mi sono appena avvicinato al flash..

    c'è qualcuno che potrebbe farlo oppure dirmi come fare???

    Grazie :)

+ Reply to Thread

Similar Threads

  1. Flash Game Tutorial
    By Flep in forum Tutorials
    Replies: 32
    Last Post: 3 Weeks Ago, 21:33
  2. gioco memory
    By ramapo99 in forum Flash Italiano
    Replies: 1
    Last Post: 16-09-09, 07:33
  3. Memory Game - gioco Flash CS3
    By Flep in forum Utilità di FlepStudio
    Replies: 21
    Last Post: 16-03-09, 09:13
  4. Replies: 19
    Last Post: 04-12-08, 15:09
  5. remove [gioco]
    By Charlotte17 in forum Actionscript 3.0 avanzato
    Replies: 6
    Last Post: 03-06-08, 17:52

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts

Search Engine Optimization by vBSEO