Heheh, kind of funny. You know... a scripter... requesting a script. Heh.
Jokes aside, I was wondering if anybody wants to fulfill a request of mine. A split screen versus mode was something I had in mind for this project I'm working on, but I don't quite have the knowhow when it comes to implementing that.
I want to let players have the option to decide between splitting the screen horizontally or vertically, and to have both players share the same map.
And maybe a variable I could use to refer to the second player.
2-Player Split Screen Effect?
● ARCHIVED · READ-ONLY
-
-
I tried to implement something like this but couldn't figure out how to nicely split the screen without duplicating code.
SceneManager would need to be rewritten so that each player has their own scene managers, same with data manager and battle manager. After that I looked into the spriteset viewports so that I could cut it in half, and then decide where the origin was based on which "player" they were (eg: left/right for 2-player, 4 corners for 4-player), and use an updated Graphics module to return the appropriate width/height
But it didn't work out. Couldn't figure out how the map was drawn at all.
I've seen a couple implementations but they basically re-wrote the entire codebase by copying everything and creating "2p" versions. -
is there a 2p option for ace?
-
Not by default but you can just define a new set of keys for a new player and then have both players on the screen at the same time. Then you effectively have 2p, except any event triggers would affect both players because everything still assumes 1p.
-
For a split screen, isn't enough to have just two spriteset. Events have to be handled twice. Messages and windows have to be resized. If you want the single player to be able to use his menu while the other player walks around, you also have to put every menu on map or have two different scenes running.
We can avoid the last part, but it isn't good that player 1 can't move if player 2 is talking to an event. And also changing map for a single player, isn't too immediate.
It isn't difficult to do (well, a bit xD) but there are many things to rewrite. And it will be easily incompatible to whatever.
So it depends of what you want to sacrifice and what you need to have.
I suggest you, since you're a scripter, to try it yourself :)
Watch other split screen scripts, if you need. I developed my first split screen in XP (it came out ugly, but it impressed people anyway ^^) and my second in VX, which came out better, but before to make one in VX Ace I want to learn more, since I want it to be compatible, someway. Else nobody would use that and I'd wasted my time. -
How did you deal with global variables? Did you just duplicate them for player 2?
-
Do you mean these?
Code:I made an array when needed and changed the various Game_ to accept a parameter that says which player refers to.$game_temp = [Game_Temp.new, Game_Temp.new] $game_message = [Game_Message.new(0), Game_Message.new(1)] $game_system = [Game_System.new(0), Game_System.new(1)] $game_switches = Game_Switches.new $game_variables = Game_Variables.new $game_self_switches = Game_SelfSwitches.new $game_actors = Game_Actors.new $game_party = [Game_Party.new(0), Game_Party.new(1)] $game_troop = [Game_Troop.new(0), Game_Troop.new(1)] $game_map = [] $game_map[0] = Game_Map.new(0) $game_map[1] = Game_Map.new(1)
This way more than two players could be simply added.
To paste just an example, the Game_System became like this:
Code:Then the major code is on the map classes.class Game_System # [...] def initialize(p) # [...] @p = p end # [...] def update if @timer_working and @timer > 0 @timer -= 1 if @timer == 0 and $game_temp[@p].in_battle # If the timer 0 in battle $game_temp[@p].next_scene = "map" # interrupt the battle end end end end
But I don't really like this system :/ I was searching for something better. -
Do you think there is a way to make it so that you can run two separate instances of the game (eg: they have their own global variables and everything) in one game.exe instance?
Here is my solution to the windows and viewports.
I approach it by simply offsetting the position based on the current scene. It can be extended to arbitrary number of players given the appropriate calculations, but it is not useful for more than 2 players because the resolution is just too small. Until we find a way to make it at least 1024x768 or something it is not feasible to have split screen for multiplayer. But DS-style split screen controls is fine.


Code:Start the game like this# assumes a vertical split module SceneManager class << self attr_reader :id #which instance of the game is this? left or right end def self.run(id=0) @id = id tsuki_run(id) end end module Graphics class << self alias :th_split_screen_width :width end def self.width return th_split_screen_width / 2 end end class Viewport alias :th_split_screen_init :initialize def initialize(*args) if args.count == 0 x = SceneManager.id * Graphics.width th_split_screen_init(x, 0, Graphics.width, Graphics.height) elsif args.count == 4 th_split_screen_init(*args) else th_split_screen_init(*args) end end end class Window alias :th_split_screen_init :initialize def initialize(x, y, width, height) x += SceneManager.id * Graphics.width th_split_screen_init(x, y, width, height) end end
Code:This means I don't have to write new windows for each screen; I just need to write a single window and let the offsets do their job.# if you want to be on the left side rgss_main { SceneManager.run(0) } # if you want to be on the right side rgss_main { SceneManager.run(1) }
However, ignoring two-player gaming, I can use this to achieve a player-switch game where you have to switch between actors in two screens, and coordinate them as such.
I think that is a more realistic goal at the moment rather than trying to get two completely different players running at the same time. -
I like the method you're using!
And VX Ace handles menus' sizes automatically, thing that VX didn't do, so everything is adapted without editing, once you specific the size.
The same thing should be done for Sprite, right? Or mmh... maybe this will depend on Sprite object having a Viewport set or not.
For the rgss_main mh, could Fiber be used? I don't know very well how they work, really, but I remember they are used to let multiple tasks work.
I made this:
Code:(it could be simplified with an array, and Fiber should resume only if fib.alive?)class Scene_Base alias :mik_update_basic :update_basic def update_basic mik_update_basic Fiber.yield end end fib1 = Fiber.new do rgss_main { SceneManager.run(0) } end fib2 = Fiber.new do rgss_main { SceneManager.run(1) } end loop do p 1; fib1.resume p 2; fib2.resume end
This way both main will be updated (you'll see on the console 1-2-1-2-1-2...), but it still doesn't work, global variables have to be duplicated. -
One of the scenes is disposed immediately. Is this because we only have reference to one of the maps (eg: $game_map) and so the other is eliminated? I'm not sure if there are actually two instances of SceneManager or just one. We might have to make it so that there are two.
For global variables, I was thinking maybe we can do something like
1: change DataManager to a class, and have each instance create their own DataManager
2: replace all references to $game_... and change them to DataManager method calls, such as DataManager.player.____
DataManager holds references to @game_player, @game_map, etc. which is basically the same as what $game_player and $game_map were for and then we don't need to duplicate code at all.
We would still keep certain global variables, but they have to be updated to be thread-safe. For example, $game_actors might be shared between both instances. You can't have duplicate actors, but each player can choose who they want in their party.
I don't mind breaking compatibility with every script if we have to; I just don't want duplicate code, nor do I want to hardcode anything like indices. DataManager and SceneManager should handle all instance-specific details internally.
....
Another (very hack-ish, might not be possible) way is to possibly change object access.
For example, suppose I define
Code:This means that everytime we sayclass Game_Players def initialize @data = [Game_Player.new, Game_Player.new] end def . return @data[SceneManager.id] end end
Code:It actually is an array access and returning a specific Game_Player object.$game_player.do_this
LOL that would be so bad, but it would make testing really simple...
....
For sprites, they are just specified using their x,y coordinates and is based on the viewport they are drawn in. Which means you basically don't have to touch them! An example is the sprites on the map (Sprite_Character)
As for VX...
Code:EDIT:def initialize(actor) super(0, 0, 544, 416) # lol @actor = actor refresh end
lol how about this for some quick testing
Code:I thought it was pretty amusing since our wrapper classes can just contain no real method definitions and so method_missing will almost always be invoked......class Game_Players def initialize @data = [Game_Player.new, Game_Player.new] end def method_missing(method) @data[SceneManager.id].send(method) end end $game_player = Game_Players.new $game_player.do_something # no method exception? Find the correct player to call the method on
Note that this is not a serious solution. The fact that we're relying on exceptions to get things to work is just silly. However if it helps eliminate the global variable problem so that we can get on with the rest of the script it's not too bad...